package info.batcloud.fanli.core.service;

import com.ctospace.archit.common.pagination.Paging;
import com.ctospace.archit.common.pagination.PagingParam;
import info.batcloud.fanli.core.dto.UserDTO;
import info.batcloud.fanli.core.domain.DefaultUserDetails;
import info.batcloud.fanli.core.domain.Result;
import info.batcloud.fanli.core.entity.TaobaoOauth;
import info.batcloud.fanli.core.enums.*;
import info.batcloud.fanli.core.settings.UserUpgradeSetting;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;

import javax.validation.constraints.NotNull;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

public interface UserService extends UserDetailsService {

    UserDetails findByTaobaoOauth(TaobaoOauth taobaoOauth);

    RegisterResult registerUser(UserRegisterParam param);

    RegisterResult registerUser(WeixinUserRegisterParam param);

    File exportUser(ExportParam param) throws IOException;

    String findTaobaoSpecialId(long userId);
    String findOrGenerateTaobaoSpecialId(long userId);
    String findTaobaoRelationId(long userId);
    String findOrGenerateTaobaoRelationId(long userId);

    void clearTaobaoRelationId(long userId);
    void clearTaobaoSpecialId(long userId);

    Result findPassword(UserFindPwdParam param);

    String getUserOpenId(long userId);

    Long getUserIdByOpenId(String openId);

    Result modifyPassword(ModifyPwdParam pwdParam);

    String findUserInvitationCode(long userId);

    UserUpgradeSetting.Upgrade findUpgradeByUserLevel(UserLevel userLevel);

    String genInvitationCode();

    String genInvitationShareSvgXml(String invitationCode, String bgImg);

    void genInvitationShareSvg(String invitationCode, String bgImg, OutputStream os);

    void lockUser(long id, boolean lock);

    void deleteUser(long id);

    UserDTO findById(long id);

    ProfileIntegrity checkUserProfileIntegrity(long userId);

    void trace(long userId, LoginTraceInfo traceInfo);

    UserDTO findByPhone(String phone);

    boolean isUserLevel(long userId, UserLevel userLevel);

    UserDTO setUserDistrict(long userId, long districtId);

    String getTaobaoPidByUserId(long userId);

    Long getTaobaoAdzoneIdByUserId(long userId);

    long getJdPositionIdByUserId(long userId);

    String getPddPidByUserId(long userId);

    UserLevel findUserLevelByUserId(long userId);

    void setUserLevel(long userId, UserLevel level);

    boolean isInvitationCodeExists(String invitationCode);

    boolean updateUserField(FieldUpdateParam param);

    Result bindPhone(BindPhoneParam param);

    CheckUserDirectlyUpgradeResult checkUserDirectlyUpgrade(long userId);

    int countUserBySuperUserId(long userId);

    String determineUserAvatar(String avatarUrl);

    String determineUserNickname(String nickname);

    List<Long> filterUserLevelUserIds(List<Long> relationPathIds, UserLevel userLevel);

    DefaultUserDetails loadUserByWeixinOpenId(String weixinOpenId);

    DefaultUserDetails loadUserByWeixinUnionId(String weixinUnionId);

    DefaultUserDetails loadUserByUserId(long userId);

    boolean bindWeixin(long userId, String weixinCode);

    boolean bindWeixinOpenId(long userId, String openId);

    /**
     * 更改用户的会员以及有效期
     * 如果当前会员的级别跟更改的级别一致，那么则视为续期
     */
    void changeUserLevel(long userId, UserLevel userLevel, int month);

    UserLevelCheckUpgradeResult checkUpgradeUserLevel(long userId);

    void changeSuperUser(long userId, Long superUserId);

    UpgradeFee checkUpgradeFee(UserLevel userLevel, TimeUnit timeUnit);

    Paging<UserDTO> search(SearchParam param);

    class ExportParam extends SearchParam {

        private int maxCount = 100;

        public int getMaxCount() {
            return maxCount;
        }

        public void setMaxCount(int maxCount) {
            this.maxCount = maxCount;
        }
    }

    class CheckUserDirectlyUpgradeResult {
        private boolean success;
        private UserLevel userLevel;

        public boolean isSuccess() {
            return success;
        }

        public void setSuccess(boolean success) {
            this.success = success;
        }

        public UserLevel getUserLevel() {
            return userLevel;
        }

        public void setUserLevel(UserLevel userLevel) {
            this.userLevel = userLevel;
        }
    }

    class LoginTraceInfo {
        private String ip;
        private UserLogType type;

        public UserLogType getType() {
            return type;
        }

        public void setType(UserLogType type) {
            this.type = type;
        }

        public String getIp() {
            return ip;
        }

        public void setIp(String ip) {
            this.ip = ip;
        }
    }

    class ProfileIntegrity {
        private boolean phone;
        private boolean region;
        private boolean weixin;
        private boolean superUser;

        public boolean isSuperUser() {
            return superUser;
        }

        public void setSuperUser(boolean superUser) {
            this.superUser = superUser;
        }

        public boolean isWeixin() {
            return weixin;
        }

        public void setWeixin(boolean weixin) {
            this.weixin = weixin;
        }

        public boolean isPhone() {
            return phone;
        }

        public void setPhone(boolean phone) {
            this.phone = phone;
        }

        public boolean isRegion() {
            return region;
        }

        public void setRegion(boolean region) {
            this.region = region;
        }
    }

    class SearchParam extends PagingParam {
        private String phone;
        private Long cityId;
        private Long provinceId;
        private Long districtId;
        private Boolean locked;
        private UserLevel level;
        private Boolean userLevelValid;
        private String relationPath;
        private String startRelationPath;
        private Long id;

        private UserSort sort;

        public String getStartRelationPath() {
            return startRelationPath;
        }

        public void setStartRelationPath(String startRelationPath) {
            this.startRelationPath = startRelationPath;
        }

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public String getRelationPath() {
            return relationPath;
        }

        public void setRelationPath(String relationPath) {
            this.relationPath = relationPath;
        }

        public UserSort getSort() {
            return sort;
        }

        public void setSort(UserSort sort) {
            this.sort = sort;
        }

        public Long getCityId() {
            return cityId;
        }

        public void setCityId(Long cityId) {
            this.cityId = cityId;
        }

        public Long getProvinceId() {
            return provinceId;
        }

        public void setProvinceId(Long provinceId) {
            this.provinceId = provinceId;
        }

        public Long getDistrictId() {
            return districtId;
        }

        public void setDistrictId(Long districtId) {
            this.districtId = districtId;
        }

        public Boolean getLocked() {
            return locked;
        }

        public void setLocked(Boolean locked) {
            this.locked = locked;
        }

        public UserLevel getLevel() {
            return level;
        }

        public void setLevel(UserLevel level) {
            this.level = level;
        }

        public Boolean getUserLevelValid() {
            return userLevelValid;
        }

        public void setUserLevelValid(Boolean userLevelValid) {
            this.userLevelValid = userLevelValid;
        }

        public String getPhone() {
            return phone;
        }

        public void setPhone(String phone) {
            this.phone = phone;
        }
    }

    class CheckUpgradeUserLevelParam {
        private TimeUnit timeUnit;
        private OrderPayType payType;

        public TimeUnit getTimeUnit() {
            return timeUnit;
        }

        public void setTimeUnit(TimeUnit timeUnit) {
            this.timeUnit = timeUnit;
        }

        public OrderPayType getPayType() {
            return payType;
        }

        public void setPayType(OrderPayType payType) {
            this.payType = payType;
        }
    }

    class UpgradeFee {
        private float price;
        private TimeUnit timeUnit;

        public UpgradeFee() {

        }

        public UpgradeFee(TimeUnit timeUnit, float price) {
            this.timeUnit = timeUnit;
            this.price = price;
        }

        public float getPrice() {
            return price;
        }

        public void setPrice(float price) {
            this.price = price;
        }

        public TimeUnit getTimeUnit() {
            return timeUnit;
        }

        public String getTimeUnitTitle() {
            return timeUnit == null ? null : timeUnit.getTitle();
        }

        public void setTimeUnit(TimeUnit timeUnit) {
            this.timeUnit = timeUnit;
        }
    }

    class FieldUpdateParam {
        private String field;
        private Long userId;
        private String value;

        public String getField() {
            return field;
        }

        public void setField(String field) {
            this.field = field;
        }

        public Long getUserId() {
            return userId;
        }

        public void setUserId(Long userId) {
            this.userId = userId;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }
    }

    class BindPhoneParam {
        @NotNull
        private String phone;
        private Long userId;

        @NotNull
        private String verifyCode;

        public Long getUserId() {
            return userId;
        }

        public void setUserId(Long userId) {
            this.userId = userId;
        }

        public String getVerifyCode() {
            return verifyCode;
        }

        public void setVerifyCode(String verifyCode) {
            this.verifyCode = verifyCode;
        }

        public String getPhone() {
            return phone;
        }

        public void setPhone(String phone) {
            this.phone = phone;
        }

    }

    class RegisterResult extends Result {
        private long userId;

        public long getUserId() {
            return userId;
        }

        public void setUserId(long userId) {
            this.userId = userId;
        }
    }

    class WeixinUserRegisterParam {

        @NotNull
        private String invitationCode;

        private String weixinBindOpenId;

        private String unionId;

        public String getUnionId() {
            return unionId;
        }

        public void setUnionId(String unionId) {
            this.unionId = unionId;
        }

        public String getInvitationCode() {
            return invitationCode;
        }

        public void setInvitationCode(String invitationCode) {
            this.invitationCode = invitationCode;
        }

        public String getWeixinBindOpenId() {
            return weixinBindOpenId;
        }

        public void setWeixinBindOpenId(String weixinBindOpenId) {
            this.weixinBindOpenId = weixinBindOpenId;
        }
    }

    class UserRegisterParam {

        @NotNull
        private String phone;
        @NotNull
        private String invitationCode;
        @NotNull
        private String password;

        @NotNull
        private String verifyCode;

        private String weixinBindOpenId;

        public String getWeixinBindOpenId() {
            return weixinBindOpenId;
        }

        public void setWeixinBindOpenId(String weixinBindOpenId) {
            this.weixinBindOpenId = weixinBindOpenId;
        }

        public String getVerifyCode() {
            return verifyCode;
        }

        public void setVerifyCode(String verifyCode) {
            this.verifyCode = verifyCode;
        }

        public String getPhone() {
            return phone;
        }

        public void setPhone(String phone) {
            this.phone = phone;
        }

        public String getInvitationCode() {
            return invitationCode;
        }

        public void setInvitationCode(String invitationCode) {
            this.invitationCode = invitationCode;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }
    }

    class ModifyPwdParam {
        @NotNull
        private String oldPassword;
        @NotNull
        private String password;
        private Long userId;

        public String getOldPassword() {
            return oldPassword;
        }

        public void setOldPassword(String oldPassword) {
            this.oldPassword = oldPassword;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        public Long getUserId() {
            return userId;
        }

        public void setUserId(Long userId) {
            this.userId = userId;
        }
    }

    class UserFindPwdParam {
        @NotNull
        private String phone;
        @NotNull
        private String password;

        @NotNull
        private String verifyCode;

        public String getVerifyCode() {
            return verifyCode;
        }

        public void setVerifyCode(String verifyCode) {
            this.verifyCode = verifyCode;
        }

        public String getPhone() {
            return phone;
        }

        public void setPhone(String phone) {
            this.phone = phone;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }
    }

    class UserLevelCheckUpgradeResult extends Result {
        private UserLevel userLevel;
        private Long orderId;
        private boolean waitPay;
        private UserUpgradePayType payType;

        private List<UpgradeFee> upgradeFeeList;

        public List<UpgradeFee> getUpgradeFeeList() {
            return upgradeFeeList;
        }

        public void setUpgradeFeeList(List<UpgradeFee> upgradeFeeList) {
            this.upgradeFeeList = upgradeFeeList;
        }

        public UserUpgradePayType getPayType() {
            return payType;
        }

        public void setPayType(UserUpgradePayType payType) {
            this.payType = payType;
        }

        public boolean isWaitPay() {
            return waitPay;
        }

        public void setWaitPay(boolean waitPay) {
            this.waitPay = waitPay;
        }

        public Long getOrderId() {
            return orderId;
        }

        public void setOrderId(Long orderId) {
            this.orderId = orderId;
        }

        public UserLevel getUserLevel() {
            return userLevel;
        }

        public void setUserLevel(UserLevel userLevel) {
            this.userLevel = userLevel;
        }
    }
}
